#pragma once
#include <iostream>
#include <algorithm>

using namespace std;

template<class T>
class interval
{
private:
	T lower;
	T upper;
public:

	interval()
	{
		lower = upper = 0;
	}

	interval(T mean, double procent)
	{
		lower = (T)(mean - mean * procent / 100);
		upper = (T)(mean + mean * procent / 100);
	}

	~interval()	{ }

	friend interval<T> operator+(const interval<T> &lop, const interval<T> &rop)
	{
		interval<T> i;
		i.lower = lop.lower + rop.lower;
		i.upper = lop.upper + rop.upper;
		return i;
	}

	friend interval<T> operator-(const interval<T> &lop, const interval<T> &rop)
	{
		interval<T> i;
		i.lower = lop.lower - rop.upper;
		i.upper = lop.upper - rop.lower;
		return i;
	}

	friend interval<T> operator*(const interval<T> &lop, const interval<T> &rop)
	{
		interval<T> i;
		i.lower = min(min(lop.lower*rop.lower, lop.lower*rop.upper), min(lop.upper*rop.lower, lop.upper*rop.upper));
		i.upper = max(max(lop.lower*rop.lower, lop.lower*rop.upper), max(lop.upper*rop.lower, lop.upper*rop.upper));
		/*auto result = minmax(lop.lower*rop.lower, lop.lower*rop.upper, lop.upper*rop.lower, lop.upper*rop.upper,
			lop.lower*rop.lower, lop.lower*rop.upper, lop.upper*rop.lower, lop.upper*rop.upper);
		i.lower = result.first;
		i.upper = result.second;*/
		return i;
	}

	friend interval<T> operator/(const interval<T> &lop, const interval<T> &rop)
	{
		interval<T> i;
		i.lower = 1 / rop.upper;
		i.upper = 1 / rop.lower;
		return lop * i;
	}

	friend ostream& operator<<(ostream &out, const interval<T> &i)
	{
		out << "[" << i.lower << ", " << i.upper << "]";
		return out;
	}

	double percentage_error()
	{
		double percent = (upper - lower) / 2 / mean();
		if (percent == 0 && upper != lower)
		{
			percent = ((double)upper - (double)lower) / 2.0 / (double)mean();
		}
		return percent;
	}

	T mean()
	{
		return (lower + upper) / 2;
	}

	T absolute_error()
	{
		return mean() - lower;
	}
};

